/*
 * Player.java
 *
 * 08/11/2009
 */
package kg.sound.player.media;

import java.io.File;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;

import javazoom.spi.mpeg.sampled.file.MpegEncoding;

/**
 * @author fernando
 */
abstract class Player {
	
	protected AudioInputStream stream;

	final void play(File file) throws Exception {
		stream = loadAndDecode(file);
		start();
	}
	
	private AudioInputStream loadAndDecode(File file) throws Exception {
		AudioInputStream in = AudioSystem.getAudioInputStream(file);
		
		/* Get the audio format for the data in the stream */
		AudioFormat baseFormat = in.getFormat();
		AudioFormat decodedFormat = null;
		
        /* Convert ULAW/ALAW formats to PCM format */
		if ((baseFormat.getEncoding() == AudioFormat.Encoding.ULAW)
				|| (baseFormat.getEncoding() == AudioFormat.Encoding.ALAW)) {
			decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
							baseFormat.getSampleRate(),
							baseFormat.getSampleSizeInBits() * 2,
							baseFormat.getChannels(), 
							baseFormat.getFrameSize() * 2,
							baseFormat.getFrameRate(), true);  // big endian
        }
        
		/* Convert MP3 formats to PCM format */
		else if ((baseFormat.getEncoding() == MpegEncoding.MPEG1L1)
				|| (baseFormat.getEncoding() == MpegEncoding.MPEG1L2)
				|| (baseFormat.getEncoding() == MpegEncoding.MPEG1L3)
				|| (baseFormat.getEncoding() == MpegEncoding.MPEG2DOT5L1)
				|| (baseFormat.getEncoding() == MpegEncoding.MPEG2DOT5L2)
				|| (baseFormat.getEncoding() == MpegEncoding.MPEG2DOT5L3)
				|| (baseFormat.getEncoding() == MpegEncoding.MPEG2L1)
				|| (baseFormat.getEncoding() == MpegEncoding.MPEG2L2)
				|| (baseFormat.getEncoding() == MpegEncoding.MPEG2L3)) {
			decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
							baseFormat.getSampleRate(), 
							16, 
							baseFormat.getChannels(),
							baseFormat.getChannels() * 2, 
							baseFormat.getSampleRate(),
							true);
		}

		/* Return the input stream or the decoded input stream as needed */
		return (decodedFormat == null) 
				? in : AudioSystem.getAudioInputStream(decodedFormat, in);
	}
	
	abstract protected void start() throws Exception;

	abstract void stop();

	abstract void purge();

}
